using System;
using System.Collections.Generic;
using System.IO;
using Cysharp.Threading.Tasks;
using Framework.Helper;
using Framework.Interface;
using Framework.Singleton;
using Shared.App;
using UnityEngine;

namespace Framework.Manager
{
    public class HotfixManager : Singleton<HotfixManager>, IManager
    {
        private Dictionary<string, ChecksumData> streamingAssetsChecksum;
        private Dictionary<string, ChecksumData> hotfixChecksum;
        private readonly Dictionary<string, bool> hotfixMap = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
        
        public async UniTask Initialize()
        {
            if (!AppDefine.editorOpenHotfix)
                return;
            
            streamingAssetsChecksum = await LoadChecksum(
                $"{FileHelper.streamingFolder}/{FileHelper.checksumHotfixeFile}",
                FileHelper.checksumName,
                true
            );

            hotfixChecksum = await LoadChecksum(
                $"{FileHelper.hotfixFolder}/{FileHelper.checksumHotfixeFile}",
                FileHelper.checksumName
            );

            VerifyHotfix();
        }

        public void Shutdown()
        {
            streamingAssetsChecksum = null;
            hotfixChecksum = null;
            hotfixMap.Clear();
        }

        public string CheckHotfixAssetBundlePath(string bundleName)
        {
            if (hotfixMap == null)
                return "";

            if (hotfixMap.TryGetValue(bundleName, out bool hotfixed))
            {
                return $"{FileHelper.hotfixFolder}/{bundleName}";
            }

            return "";
        }

        private void VerifyHotfix()
        {
            foreach (KeyValuePair<string,ChecksumData> hotfix in hotfixChecksum)
            {
                if (!streamingAssetsChecksum.ContainsKey(hotfix.Value.filename))
                {
                    hotfixMap[hotfix.Value.filename] = true;
                }
                else if (!hotfix.Value.checksum.Equals(streamingAssetsChecksum[hotfix.Key].checksum))
                {
                    hotfixMap[hotfix.Value.filename] = true;
                }
            }
        }
        
        private async UniTask<Dictionary<string, ChecksumData>> LoadChecksum(string path, string assetName, bool loadFromStreamingAssets = false)
        {
            // Debug.Log("[HotfixManager] LoadChecksum ===> " + path);
            Dictionary<string, ChecksumData> dic = new Dictionary<string, ChecksumData>();
            
            if (!File.Exists(path) && !loadFromStreamingAssets)
            {
                return dic;
            }

            AssetBundle bundle = null;

            try
            {
                Debug.Log("[HotfixManager] " + path);
                bundle = await AssetBundleHelper.LoadAssetBundleAsync(path, false);
            }
            catch (Exception e)
            {
                Debug.Log($"load checksum at {path} occurs error, error: {e.Message}");
            }
            
            if (bundle == null)
            {
                Debug.LogFormat("file [{0}] yout to load is not exist !", path);
                return dic;
            }

            var asset = bundle.LoadAsset<ResourceChecksumData>(assetName);
            for (int i = 0; i < asset.ChecksumList.Count; i++)
            {
                dic[asset.ChecksumList[i].filename] = asset.ChecksumList[i];
            }

            bundle.Unload(false);
            
            return dic;
        }
    }
}